import std.stdio:writefln;
import std.random;
import Perceptron;
import ImageIO;
import Images;

public class PerceptronsMatrix{
	Perceptron[][] perceptrons;
	int width;
	int height;

	this(int width, int height){
		this.width = width;
		this.height = height;
		perceptrons.length = height;
		foreach(inout line; perceptrons){
			line.length = width;
			foreach(inout per; line)
				per = new Perceptron(width * height);
		}
	}

	private int[] scal(ImageIO img){
    	int[] ret;

		foreach(line;img.pixels)
			foreach(point;line)
				if(point == img.foreground)
					ret ~= 1;
				else
					ret ~= 0;
		assert(ret.length == width * height);
    	return ret;
	}

    private void zaburz(inout int[] a){
        for(int i = 0; i < a.length; i++){
            int prob = (rand() % 100);
            if(prob < 10)
                a[i] = !a[i];
        }
    }

	void train(Images images,int iterations){
		int num;
		int expect;
        int[] inputOrg = new int[width * height];
        int[] inputPerm = new int[width * height];
		
		for(int i = 0; i < iterations; i++){
			writefln(i);
			num = rand() % images.images.length;
			inputOrg[] = scal(images.images[num]);
			inputPerm[] = inputOrg[];
			zaburz(inputPerm);
			foreach(int x, inout line; perceptrons)
				foreach(int y, inout per; line){
					if(inputOrg[x*width + y] == 1)	expect = 1;
					else expect = -1;
					per.train(inputPerm, expect);
				}
		}
        foreach(int x, inout line; perceptrons)
	        foreach(int y, inout per; line)
				per.endTraining();
	}

	void detect(ImageI imgIn, inout ImageIO imgOut){
		writefln("Odszumiam...");
		foreach(int i, inout lineOut; imgOut.pixels)
			foreach(int j,inout pointOut; lineOut){
				int res = perceptrons[i][j].detect(scal(imgIn));
				if(res == 1) pointOut = imgOut.foreground;
				else if(res == 0 || res == -1) pointOut = imgOut.background;
			}
		writefln("Done.");
	}

}
